/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once
#pragma warning( disable : 4244)
#include "../game/PhysicsObject.h"
#include "../game/IEntity.h"

#include <deque>

/**
=========================
A movable camera
=========================
*/
class ICamera
{
public:
    /** Update the camera to another location if needed */
	virtual void Update(float dt)=0;

    /** Point the camera at a location */
    virtual void LookAt( const Vector2f &pos )=0;
    /** Move the Camera over time to this new location, multiplied by the speed var */
    virtual void MoveTo( const Vector2f &dest ) =0;
    /** Shake the camera for a duration and a velocity */
    virtual void Shake( float time, float magnitude )=0;

    /** Set a path for the camera to follow */
    void SetPath( std::deque<Vector2f> pathToFollow ) { m_pathToFollow = pathToFollow; };
    /** Add to path */
    void AddToPath( const Vector2f &v ) { m_pathToFollow.push_front( v ); };
    /** Attach to an entity */
    void Attach( IEntity* ent ) 
    {   ent->m_flags |= EF_ATTACHED_TO_CAMERA; 
        m_entityToFollow = ent;
        m_oldBaseVel = m_baseVel;
        m_baseVel = Vector2f( ent->m_fSpeed,ent->m_fSpeed); 
        MoveTo( ent->m_physObject.GetPosition() );
    }; 
    /** Detach */
    void Detach( IEntity *ent )
    { 
        ent->m_flags &= ~EF_ATTACHED_TO_CAMERA;
        m_entityToFollow = NULL;
        m_baseVel = m_oldBaseVel;
    };
    /** Test if this entity is attached to this camera */
    bool IsAttached( IEntity* ent ) { return m_entityToFollow == ent; };


    /** Test to see if this rectangle intersects with the viewport */
    bool Contains( const Rect &r  ) {
        // check the map boundaries
        return !((r.x + r.width  < m_position.x)	|| 
		        (r.y + r.height < m_position.y)	    ||
                (r.x > m_position.x + m_view.width) || 
                (r.y > m_position.y + m_view.height) );
    };

    /** Test to see if this point intersects with the viewport */
    bool Contains( int x, int y ) {
        return !( x > m_position.x + m_view.width  ||
                  y > m_position.y + m_view.height ||
                  x < m_position.x ||
                  y < m_position.y );
    };

    /** Get the Screen Position of the camera */
    Vector2f GetScreenCoord() { return m_screenPos; };
    /** Set the Screen Pos */
    void SetScreenCoord(const Vector2f &pos) { m_screenPos = pos; };

    /** Get the Position of the camera (world relative) */
    Vector2f GetPosition() { return m_position; };
    /** Sets the new position, also recalculates the viewport properly */
    void SetPosition( const Vector2f &pos ) {     
        m_position = pos; 
    };

    /** Set the dimensions of the camera */
    void SetViewPort(const Rect &view ) { m_view = view; };
    Rect GetViewPort() { return Rect( m_view.x,m_view.y,/*m_position.x, m_position.y,*/ m_view.width, m_view.height); };

    /** Activate/ Deactivate this camera */
    bool IsActivated() { return m_active; };
    void Activate( bool b) { m_active = b; };

    /** Set the speed of the camera motion */
    Vector2f GetVelocity() { return m_baseVel; };
    void SetVelocity( const Vector2f &vel ) { m_baseVel = vel; };
    /** Set the friction */
    float GetFriction() { return m_friction; };
    void  SetFriction(float f) { m_friction = f; };

    /** Retreive this cams id */
    int GetID() { return m_id; };
    void SetID(int id) { m_id = id; };

    /** Test to see if this is the main camera */
    bool IsMainCamera() { return m_mainCamera; };

    /** --------- MAke this private --------------*/
    /** Set to be the main camera */
    void SetMainCamera() { m_mainCamera = true; }
    /** Remove from being the main camera */
    void SetSideCamera() { m_mainCamera = false; };

    virtual ~ICamera() {};

protected:
    bool        m_active;
    Rect        m_view;
    int         m_id;
    bool        m_mainCamera;

    /**
     * Space coords
     */
    PhysicsObject   m_phyObj;
    Vector2f        m_position;
    Vector2f        m_screenPos;
    Vector2f        m_dest;
    Vector2f        m_velocity;
    Vector2f        m_baseVel;
    Vector2f        m_oldBaseVel;   // base vel if just moving w/o latched entity
    float           m_friction;

    /** Path to follow - Takes presedence vs AttachedTo */
    typedef std::deque<Vector2f> type_Vectors;
    type_Vectors m_pathToFollow;
    // Follow this entity if the camera does not have path
    IEntity*    m_entityToFollow;
};

